﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace SpectrEngine.Framework.Collections
{

    internal sealed class UpdateableComparer
        : IComparer<IUpdateableItem>
    {
        public int Compare(IUpdateableItem x, IUpdateableItem y)
        {
            return x.UpdateOrder.CompareTo(y.UpdateOrder);
        }
    }

    public sealed class UpdateList
        : List<IUpdateableItem>
    {
        private UpdateableComparer comparer;

        private HashSet<IUpdateableItem> addList;
        private HashSet<IUpdateableItem> cullList;

        private bool dirtyFlag;

        public UpdateList()
        {
            comparer = new UpdateableComparer();
            addList = new HashSet<IUpdateableItem>();
            cullList = new HashSet<IUpdateableItem>();

            dirtyFlag = false;
        }

        public void Register(GameNode node)
        {
            node.UpdateOrderChanged += new EventHandler(node_UpdateOrderChanged);
            node.Disposed += new EventHandler(node_Disposed);
            node.EnabledChanged += new EventHandler(node_EnabledChanged);

            addList.Add(node);

            this.dirtyFlag = true;
        }

        public void UnRegister(GameNode node)
        {
            cullList.Add(node);
        }

        void node_UpdateOrderChanged(object sender, EventArgs e)
        {
            this.dirtyFlag = true;
        }

        void node_EnabledChanged(object sender, EventArgs e)
        {
            if (((IUpdateableItem)sender).Enabled)
            {
                addList.Add((IUpdateableItem)sender);
                this.dirtyFlag = true;
            }
            else
            {
                cullList.Add((IUpdateableItem)sender);
            }
        }
        
        void node_Disposed(object sender, EventArgs e)
        {
            cullList.Add((IUpdateableItem)sender);
        }

        public void Update(GameTime gameTime)
        {
            foreach (IUpdateableItem node in cullList)
            {
                this.Remove(node);
            }

            cullList.Clear();

            foreach (IUpdateableItem node in addList)
            {
                this.Add(node);
            }

            addList.Clear();

            if (dirtyFlag)
            {
                this.Sort(comparer);
            }

            foreach (IUpdateableItem node in this)
            {
                node.Update(gameTime);
            }
        }
    }
}
